#include "servernetengine.h"

#include "netmsg.h"

#include "connectmsg.h"
#include "connectreplymsg.h"
#include "sourcemsg.h"
#include "pluginmanager.h"
#include "project.h"
#include "processupdatemsg.h"
#include "resultsmsg.h"

#include <QDebug>
#include <QTcpSocket>
#include <QMutex>
#include <QDateTime>
#include <QDomDocument>


CThreadContainer::CThreadContainer(int nSocket)
		{
			m_pSocket = new QTcpSocket(this);
			m_pSocket->setSocketDescriptor(nSocket);

			// Signals & Slots.
			connect(m_pSocket, SIGNAL(disconnected()), this, SLOT(quit()));
			connect(m_pSocket, SIGNAL(readyRead()), this, SLOT(onData()));
		}
CThreadContainer::~CThreadContainer()
{
}
void CThreadContainer::onData()
		{
			static QMutex m;
			if (m.tryLock())
			{
				while (m_pSocket->bytesAvailable())
				{
					qDebug("onData()");

					CNetMsg *pMsg =0;

					QDataStream ds(m_pSocket);
					QString strError;
					pMsg = CNetMsg::getMsg(ds, &strError);

					if (pMsg)
					{
						switch (pMsg->getType())
						{
							// clients wants to connect to us and get the default config:
							case CNetMsg::MSG_TYPE_CONNECT:
							{
								onClientConnect(static_cast<CConnectMsg*>(pMsg));
							}
							break;
							case CNetMsg::MSG_TYPE_SOURCE:
							{
								onClientSource(static_cast<CSourceMsg*>(pMsg));
							}
							break;
							default:
							{
								qDebug() << "Unknown message type:" << pMsg->getType();
							}
							break;
						}
					}
					else
					{
						qDebug() << "Got NULL pMsg";
					}
					delete pMsg;
				}

				m.unlock();
			}
		}
void CThreadContainer::projectProgress(int nCurrent, int nTotal, const QString &strHint)
		{
			qDebug() << "Project progress:" << nCurrent << "/" << nTotal << " (" << strHint << ").";
			CProcessUpdateMsg msg;
			msg.setCurrent(nCurrent);
			msg.setTotal(nTotal);
			msg.setMessage(strHint);

			QDataStream ds(m_pSocket);
			QString strError;
			if (!msg.setMsg(ds, &strError))
			{
				qWarning() << "Failed to send update message:" << strError;
			}
		}
void CThreadContainer::projectFinished()
		{
				qDebug() << "Project finished";

			// get the results path then clean the project memory:
			CProject *proj = qobject_cast<CProject*>(sender());
			if (proj)
			{
				QString strResultsPath = proj->getResultsPath();
				// open results file:
				QFile f(strResultsPath);
				if (f.open(QIODevice::ReadOnly))
				{
					CResultsMsg msg;
					msg.setResultsData(f.readAll());
					QDataStream ds(m_pSocket);
					QString strError;

					if (!msg.setMsg(ds, &strError))
					{
						qDebug() << "Error sending results to client:" << strError;
					}
					f.close();
					f.remove();
				}
				else
				{
					qDebug() << "Could not open file:" << strResultsPath << "for reading!";
				}
				qDebug() << "Results are at:" << strResultsPath;

				proj->deleteLater();
			}
		}
void CThreadContainer::onClientConnect(CConnectMsg *pMsg)
		{
			qDebug() << "Connection from user" << pMsg->getUsername() << "Password is:" << pMsg->getPassword();

			CConnectReplyMsg m;
			m.setConnectionAccepted(true);
			m.setConfigPayload(CPluginManager::getPluginManager()->getPluginConfig());

			qDebug() << "Accepting connection";

			QString strError;
			QDataStream ds(m_pSocket);

			if (!m.setMsg(ds, &strError))
			{
				qDebug() << strError;
			}
		}
void CThreadContainer::onClientSource(CSourceMsg* pMsg)
		{
			qDebug() << "recieved source";
			QDir d = getNewTempPath();
			qDebug() << "Writing source to path:" << d;
			pMsg->reconstituteFiles(d);

			QDomDocument doc;
			if (!doc.setContent(pMsg->getConfigPayload()))
			{
				qDebug() << "Error: could nto set config payload";
				return;
			}

			// create a project:
			CProject *proj = new CProject(doc, d.absolutePath(), this);
			connect(proj, SIGNAL(projectProgress(int,int,QString)), this, SLOT(projectProgress(int,int,QString)));
			connect(proj, SIGNAL(projectFinished()), this, SLOT(projectFinished()));
			proj->startProject();
		}
QDir CThreadContainer::getNewTempPath() const
		{
			quint32 nRand =0;
			QDir dPath = QDir::temp();

			while (1)
			{
				nRand = qrand();
				QString strDirName = QString("cppa%1").arg(nRand,8, 16, QLatin1Char('0'));
				if (!dPath.cd(strDirName))
				{
					if ( dPath.mkdir(strDirName) &&  dPath.cd(strDirName))
					{
						// created ok - return now
						return dPath;
					}
				}
				else
				{
					// already created - try again:
					dPath.cdUp();
				}
			}
		}


CServerNetEngine::CServerNetEngine(int nSocketDescriptor)
	:  m_nSocketDescriptor(nSocketDescriptor)
{
	qsrand(QDateTime::currentDateTime().toTime_t());
}

void CServerNetEngine::run()
{
	CThreadContainer thread(m_nSocketDescriptor);

	exec();
}



